package cscie160.project.bank.security;

import cscie160.project.bank.Commands;
import cscie160.project.bank.AccountInfo;
import java.util.HashMap;
/**
 * This class implements a minimal security necessary to 
 * model access to a bank account.
 * @author Michael Melnikov   
*/
public class Security
{
    /**
    * keeps information about permitted account numbers and corresponding PINs.
    * Key is accountNumber, value is a PIN.
    * <BR>Would be kept in a database in real world
    */
    private HashMap <Integer,Integer> authorizedAccounts;
        
    /**
    * keeps information about permitted operations for accounts.
    * Key is accountNumber, value is a map of command to permission.
    * <BR>Would be kept in a database in real world
    */
    private static HashMap<Integer, HashMap<Commands, Boolean>> permissions;
    
    /**
    * no-args constructor
    */
    public Security()
    {
        this(new HashMap <Integer, Integer>());
    }
    
    /**
    * 1-arg constructor
    * @param authorizedAccounts HashMap<Integer, Integer> 
    */
    public Security(HashMap<Integer, Integer> authorizedAccounts)
    {
        super();
        this.authorizedAccounts = authorizedAccounts;
        if (Security.permissions == null)
            permissions = new HashMap<Integer, HashMap<Commands, Boolean>>();
            
        java.util.Set<Integer> acNumbers =  this.authorizedAccounts.keySet();
        java.util.Iterator<Integer> iter = acNumbers.iterator();
        while (iter.hasNext())
        {
            Integer acNumI = iter.next();
            if (acNumI == null)
                continue;
            HashMap<Commands, Boolean> perm = new HashMap<Commands, Boolean>();
            perm.put(Commands.DEPOSIT, false);
            perm.put(Commands.WITHDRAW, false);
            perm.put(Commands.BALANCE, true);
            switch (acNumI.intValue())
            {
                case 1:
                    perm.put(Commands.DEPOSIT, true);
                    perm.put(Commands.WITHDRAW, true);
                    break;
                case 2:
                    perm.put(Commands.DEPOSIT, true);
                    break;
                case 3:
                    perm.put(Commands.WITHDRAW, true);
                    break;
                default:
                    break;
            }
            permissions.put(acNumI, perm);
        }
    }

    /**
    * checks the provided account info authenticity
    * @param aInfo AccountInfo
    * @return boolean
    */    
    public boolean isAuthentic(AccountInfo aInfo)
    {
        boolean isAuthentic = true;
        int accountNum = aInfo.getAccountNumber();
        if (authorizedAccounts == null || !authorizedAccounts.containsKey(accountNum))
            isAuthentic = false;
        
        if (isAuthentic)
        {
            int accountPin = aInfo.getPin();
            if (authorizedAccounts.get(accountNum) != accountPin)
                isAuthentic = false;
        }
        return isAuthentic;
    }

    /**
    * checks the permission od requested transaction for the account
    * @param aInfo AccountInfo
    * @param command Commands 
    * @return boolean
    */    
    public boolean isPermitted(AccountInfo aInfo, Commands command)
    {
        int accountNum = aInfo.getAccountNumber();
        HashMap<Commands, Boolean> accountPermissions = permissions.get(accountNum);
        if (accountPermissions == null)
            return false;
        
        boolean operationPermission = false;
        boolean isAtomicCommand = (command == Commands.DEPOSIT || command == Commands.WITHDRAW || command == Commands.BALANCE);
        if (isAtomicCommand)
        {
            if (accountPermissions.containsKey(command))
                operationPermission = accountPermissions.get(command);
        }
        return operationPermission;
    }
}